/**
 * 
 */
package cn.nawang.ebeim.ui.util;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

import cn.nawang.ebeim.client.bean.BackStrategy;
import cn.nawang.ebeim.client.bean.BackupBean;
import cn.nawang.ebeim.client.bean.ClientConfiguration;
import cn.nawang.ebeim.client.bean.DataSource;
import cn.nawang.ebeim.client.bean.DataSourceVersion;
import cn.nawang.ebeim.client.bean.RecoveryBean;
import cn.nawang.ebeim.client.bean.StorageServer;
import cn.nawang.ebeim.client.util.CommonMethodsUtils;
import cn.nawang.ebeim.client.util.DbUtil;
import cn.nawang.ebeim.client.util.FileUtil;
import cn.nawang.ebeim.client.util.TransportUtil;
import cn.nawang.ebeim.client.util.ZipUtil;
import cn.nawang.ebeim.client.util.ZookeeperUtil;
import cn.nawang.ebeim.client.version.DirectoryNode;
import cn.nawang.ebeim.client.version.Node;
import cn.nawang.ebeim.client.version.VersionTree;
import cn.nawang.ebeim.client.version.VersionTreeUtil;
import cn.nawang.ebeim.ui.bean.Bean;
import cn.nawang.ebeim.ui.bean.DataSourceWrapper;
import cn.nawang.ebeim.ui.bean.Datasource;
import cn.nawang.ebeim.ui.bean.DatasourceConfig;

/**
 * @ClassName: UIversionTreeUtil
 * @Description: 版本树工具类
 * @author zhangjf
 * @date 2015年11月24日 上午8:58:30
 * @version v1.0
 */
public class UIversionTreeUtil {
  
  private static final Logger LOG = LoggerFactory.getLogger(UIversionTreeUtil.class);
    /**
   * @author zhangjf
   * @Description: 获取版本树
   * @param @param dsId
   * @param @param version
   * @param @return
   * @return VersionTree 
   * @date 2015年11月24日08:59:01
   *
   * @修改人 zhangjf
   * @修改日期
   */
  public static VersionTree getVersionTree(String dsId,String version){
    VersionTree tree = VersionTreeUtil.loadVersionTree(dsId, version);
    if (tree == null) {
      List<StorageServer> servers = CommonMethodsUtils.getServer();
      ClientConfiguration.setStorageServers(servers);
      tree = VersionTreeUtil.getVersionTree(dsId, version);
      try {
        ZookeeperUtil.close();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    return tree;
  }
  
  
  /**
   * @author zhangjf
   * @Description: 上传版本树
   * @param @param dsId
   * @param @param version
   * @return void 
   * @date 2015年11月24日08:59:48
   *
   * @修改人 zhangjf
   * @修改日期
   */
  public static void uploadVersionTree(String dsId,String version){
    
    String src = FileUtil.getVersionFilePath(dsId, version);
    String dst = FileUtil.getZipVersionFilePath(dsId, version) + ".zip";
    new ZipUtil().zip(src, dst);
    
    int dotIdx = version.indexOf(".");
    int versionMajor = Integer.parseInt(version.substring(0,dotIdx));
    int versionMinor = Integer.parseInt(version.substring(dotIdx+1,version.length()));
    DataSourceVersion dataSourceVersion =
        new DataSourceVersion(versionMajor, versionMinor);
    String path =
        CommonMethodsUtils.getVersionTreePath(dsId, dataSourceVersion) + ".zip";
    try {
      List<StorageServer> servers = CommonMethodsUtils.getServer();
      ClientConfiguration.setStorageServers(servers);
      TransportUtil.uploadVersionTree(dsId, version, path);
      ZookeeperUtil.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  public static DataSource getDsByDsId(String dsId){
    String dsStr = ApiUtil.getDataSourceByDsId(dsId);
    JSONObject rsJson = JSONObject.parseObject(dsStr);
    JSONObject dsJson = rsJson.getJSONObject("obj");
    DataSource ds = JSONObject.toJavaObject(dsJson, DataSource.class);
    return ds;
  }
  
  /**
   * @author zhangjf
   * @Description: 创建文件夹
   * @param @param dsId
   * @param @param version
   * @param @param path
   * @param @param folderName
   * @param @return
   * @return VersionTree 
   * @date 2015年11月24日上午11:42:19
   *
   * @修改人 zhangjf
   * @修改日期
   */
  public static String versionTreeCreateFolder(String dsId, String version, String path,String folderName){
    
    LOG.info("versionTreeCreateFolder {}",dsId,version,path,folderName);
    
    VersionTree tree = getVersionTree(dsId,version);
    if(tree==null){
      //DO SOMETHING...
    }
    DirectoryNode node = (DirectoryNode)tree.findNode(path);
    if(node==null){
      node = tree.getRoot();
    }
    folderName = existNodeRename(node.getChildren(), folderName, null);
    DirectoryNode dn = new DirectoryNode(folderName);
    dn.setHandAdd(true);
    dn.setCreateTime(new Date().getTime());
    dn.setNid(UUID.randomUUID().toString());
    dn.setParent(node);
    dn.setStatus(Node.STATUS_ADD);
    dn.setPid(node.getNid());
    Map<String,Node> map = node.getChildren();
    String p = folderName;
    map.put(p, dn);
    
    VersionTreeUtil.save(tree, dsId, version);
    uploadVersionTree(dsId, version);
    
    return "ok";
  }
  
  private static String updateDs(String dsId,int versionMajor){
    String data = ApiUtil.getDataSourceByDsId(dsId);
    JSONObject rsJson = JSONObject.parseObject(data);
    JSONObject dsJson = rsJson.getJSONObject("obj");
    DataSourceWrapper wrapper = new DataSourceWrapper();
    Datasource ds = JSONObject.toJavaObject(dsJson, Datasource.class);
    ds.setCurrentVersionMajor(versionMajor);
    BackStrategy bs = JSONObject.toJavaObject(dsJson, BackStrategy.class);
    bs.setBsId(dsJson.getString("backupStrategyId"));
    DatasourceConfig dc = JSONObject.toJavaObject(dsJson, DatasourceConfig.class);
    wrapper.setDatasource(ds);
    wrapper.setBackStrategy(bs);
    wrapper.setDatasourceConfig(dc);
    String rs = ApiUtil.updateDataSource(wrapper);
    return rs;
  }
  
  public static void main(String[] args) {
    VersionTree tree = VersionTreeUtil.getVersionTree("DS-1448441435448-158", "1.0");
    tree.visit();
    Node node = tree.findNode("/");
    System.out.println(node);
    //F:/\datasource/\safebox/\box - 副本 (20)//\aaa\box - 副本 (20)
  }
  
  /**
   * @author zhangjf
   * @Description: 导入文件夹
   * @param @param wrapper
   * @return void 
   * @date 2015年11月24日上午11:41:57
   *
   * @修改人 zhangjf
   * @修改日期
   */
  public static String importDs(DataSourceWrapper wrapper){
    String data = ApiUtil.addDataSource(wrapper);
    JSONObject dataJson = JSONObject.parseObject(data);
    String dsIdJson = dataJson.getString("dsId");
    DataSource ds =  getDsByDsId(dsIdJson);
    
    Bean bean = wrapper.getBean();
    //获取根树
    VersionTree rootTree = getVersionTree(bean.getDsId(), bean.getVersion());
    DirectoryNode node = null;
    if(bean.getPath().equals("/")){
      node = (DirectoryNode) rootTree.getRoot();
    }else{
      node = (DirectoryNode) rootTree.findNode(bean.getPath());
    }
    VersionTree tree = null;
    try {
      //生成子树，保存，上传
      tree = VersionTreeUtil.generateVersionTree(ds);
      DirectoryNode root = tree.getRoot();
      root.setPid(node.getNid());
      root.setDsId(ds.getId());
      root.setPid(node.getNid());
      root.setParent(node);
      
      String p = ds.getName();
      if(p.substring(0, 1).equals("\\")){
        p = p.substring(1,p.length());
      }
      //检查重名
      p = existNodeRename(node.getChildren(), p, null);
      root.setName(p);
      //子树添加到根树上
      node.getChildren().put(p, root);
      
      VersionTreeUtil.save(tree, ds.getId(), (ds.getCurrentVersionMajor()+1)+"."+ds.getCurrentVersionMinor());
      uploadVersionTree(ds.getId(), (ds.getCurrentVersionMajor()+1)+"."+ds.getCurrentVersionMinor());
   
    } catch (IOException e) {
      e.printStackTrace();
    }
    
    //保存和上传根树
    int v = (int) Math.floor(Double.valueOf(bean.getVersion()))+1;
    VersionTreeUtil.save(rootTree, bean.getDsId(), v+".0");
    uploadVersionTree(bean.getDsId(), v+".0");
    
    backup(dsIdJson);
    
    String rs = updateDs(bean.getDsId(),v);
    JSONObject json = JSONObject.parseObject(rs);
    json.put("version", v);
    return json.toString();
  }
  
  /**
   * @author zhangjf
   * @Description: 同名节点重命名
   * @param @param map
   * @param @param filename
   * @param @param i
   * @param @return
   * @return String 
   * @date 2015年11月26日上午9:56:51
   *
   * @修改人 zhangjf
   * @修改日期
   */
  public static String existNodeRename(Map<String,Node> map,String filename,Integer i){
    if(i==null){
      i= 1;
    }
    boolean exist = false;
    for (String key:map.keySet()) {
      if(key.equals(filename)){
        exist = true;
        break;
      }
    }
    if(exist){
      int dotP = filename.lastIndexOf(".");
      String presuffix = filename;
      String suffix = null;
      //文件名是否有后缀
      if(dotP != -1){
        //除去后缀部分
        presuffix = filename.substring(0, dotP);
        //保存后缀
        suffix = filename.substring(dotP, filename.length());
      }
      //最后一个字符
      String lastChar = presuffix.substring(presuffix.length()-1);
      String preChar = "";
      String between = "";
      int preIdx = presuffix.lastIndexOf("(");
      if(preIdx!=-1){
        //最后一个左括号
        preChar = "(";
        //最后一个左括号与最后一个字符间的字符
        between = presuffix.substring(preIdx+1,presuffix.length()-1);
      }
      String newFilename = null;
      //判断是否重命名过
      if(preChar.equals("(")&&lastChar.equals(")")&&isPositiveNum(between)){
        String forward = presuffix.substring(0, preIdx);
        newFilename = forward + "("+i+")";
      }else{
        newFilename = presuffix + "("+i+")";
      }
      if(suffix != null){
        newFilename += suffix;
      }
      exist = false;
      for (String key:map.keySet()) {
        if(key.equals(newFilename)){
          exist = true;
          break;
        }
      }
      //判断新命名是否存在，若存在，则递归调用自身。
      if(exist){
        filename = existNodeRename(map,newFilename,++i);
      }else{
        filename = newFilename;
      }
    }
    
    return filename;
  }
  
  public static boolean isPositiveNum(String str) {
    Boolean strResult = str.matches("[0-9]+");
    if (strResult == true) {
      return true;
    } else {
      return false;
    }
  }
  
  private static void backup(String dsId){
    BackupBean bean = new BackupBean();
    bean.setDsId(dsId);
    bean.setStatus(0);
    try {
      DbUtil.initConnection();
      DbUtil.initDatabase();
      DbUtil.deleteBackupTaskByDsid(dsId);
      DbUtil.addBackupTask(bean);
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  
  /**
   * @author zhangjf
   * @Description: 递归获取父节点的dsId
   * @param @param node
   * @param @return
   * @return String 
   * @date 2015年11月24日下午7:00:24
   *
   * @修改人 zhangjf
   * @修改日期
   */
  public static String getParentDsId(Node node){
    String dsId = null;
    if(node!=null && node instanceof DirectoryNode){
      dsId = ((DirectoryNode)node).getDsId();
      if(dsId == null){
        dsId = getParentDsId(node.getParent());
      }
    }
    return dsId;
  }
  
  /**
   * @author zhangjf
   * @Description: 恢复
   * @param @param node
   * @param @param rPath
   * @param @param nid
   * @param @param first 第一次调用的时候，node是否为根节点
   * @return void 
   * @date 2015年11月25日下午5:11:37
   *
   * @修改人 zhangjf
   * @修改日期
   */
  public static void recovery(Node node,String rPath,String nid,String userClickNodePath,boolean first){
    if(node instanceof DirectoryNode){
      String dsId = ((DirectoryNode) node).getDsId();
      if(dsId != null && !first){
        DataSource ds = getDsByDsId(dsId);
        
        RecoveryBean recovery = new RecoveryBean();
        recovery.setDsId(dsId);
        recovery.setPath("/");
        recovery.setVersion(ds.getCurrentVersionMajor()+"."+ds.getCurrentVersionMinor());
        recovery.setRecoveryPath(rPath);
        recovery.setNid(nid);
        recovery.setUserClickNodePath(userClickNodePath);
        LOG.info("rootTree recovery.....:"+dsId+":"+recovery.getVersion());
        try {
          DbUtil.initConnection();
          DbUtil.initDatabase();
        } catch (SQLException e) {
          e.printStackTrace();
        }
        DbUtil.addRecoveryTask(recovery);
        
      }
      Map<String,Node> map = ((DirectoryNode) node).getChildren();
      for (String key : map.keySet()) {
        Node child = map.get(key);
        recovery(child,rPath,nid,userClickNodePath,false);
      }
    }
  }
  
}
